package com.hmkj.core.service.amount.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.etonepay.b2c.entity.BackForm;
import com.etonepay.b2c.entity.PayForm;
import com.hmkj.common.baseMapper.GenericMapper;
import com.hmkj.common.baseMapper.GenericPo;
import com.hmkj.common.utils.*;
import com.hmkj.core.api.etonepay.EtonePayUtil;
import com.hmkj.core.api.hrpay.HRPayUtils;
import com.hmkj.core.api.lianlian.PartnerConfig;
import com.hmkj.core.api.lianlian.PayDataBean;
import com.hmkj.core.api.lianlian.PaymentInfo;
import com.hmkj.core.api.lianlian.enums.PayResultEnum;
import com.hmkj.core.api.lianlian.util.YinTongUtil;
import com.hmkj.core.api.ninepai.RpmUtils;
import com.hmkj.core.api.umf.domain.ResultCode;
import com.hmkj.core.constant.CacheID;
import com.hmkj.core.constant.ConfigNID;
import com.hmkj.core.constant.Constants;
import com.hmkj.core.constant.PointNid;
import com.hmkj.core.exception.BussinessException;
import com.hmkj.core.mapper.amount.AccountLogMapper;
import com.hmkj.core.mapper.amount.AccountMapper;
import com.hmkj.core.mapper.amount.CashMapper;
import com.hmkj.core.mapper.amount.RechargeMapper;
import com.hmkj.core.mapper.system.BankMapper;
import com.hmkj.core.mapper.user.UserBankMapper;
import com.hmkj.core.mapper.user.UserFreezeMapper;
import com.hmkj.core.mapper.user.UserMapper;
import com.hmkj.core.model.amount.RechargeModel;
import com.hmkj.core.model.pay.PayResult;
import com.hmkj.core.po.amount.Account;
import com.hmkj.core.po.amount.AccountLog;
import com.hmkj.core.po.amount.Recharge;
import com.hmkj.core.po.system.Bank;
import com.hmkj.core.po.user.User;
import com.hmkj.core.po.user.UserBank;
import com.hmkj.core.po.user.UserFreeze;
import com.hmkj.core.service.amount.RechargeService;
import com.hmkj.core.service.cache.LockService;
import com.hmkj.core.service.cache.RedisService;
import com.hmkj.core.service.operate.PointRuleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 充值记录业务相关Service接口实现<br>
 *
 * @author donfy
 * @date 2017-08-15 08:16:12
 */
@Slf4j
@Service
@Scope("prototype")
@Transactional(rollbackFor = Exception.class)
public class RechargeServiceImpl implements RechargeService {

    @Resource
    private RechargeMapper rechargeMapper;
    @Resource
    private AccountMapper accountMapper;
    @Resource
    private AccountLogMapper accountLogMapper;
    @Resource
    private CashMapper cashMapper;
    @Resource
    private RedisService redisService;
    @Resource
    private LockService lockService;
    @Resource
    private PointRuleService pointRuleService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserFreezeMapper userFreezeMapper;
    @Resource
    private UserBankMapper userBankMapper;
    @Resource
    private BankMapper bankMapper;

    @Override
    public GenericMapper<Recharge, Integer> _getMapper() {
        return rechargeMapper;
    }


    @Override
    public void doAudit(RechargeModel model) throws Exception {
        // 充值参数校验
        Recharge recharge = rechargeMapper.selectByPrimaryKey(model.getId());
        if (null == recharge) {
            throw new BussinessException("充值记录不存在");
        }
        if (recharge.getStatus() != Recharge.STATUS.T2.code) {
            throw new BussinessException("充值订单状态已更改请刷新后重试");
        }
        if (BigDecimalUtils.isLessThan(recharge.getAmount(), model.getActualArrival())) {
            throw new BussinessException("实际到账金额不能大于订单金额");
        }
        //更新充值订单信息
        recharge.setStatus(model.getStatus());
        recharge.setActualArrival(model.getActualArrival());
//        recharge.setFee(BigDecimalUtils.sub(recharge.getAmount(), model.getActualArrival()));//充值手续费 = 订单金额 - 实际到账金额
        recharge.setFee(BigDecimal.ZERO);
        recharge.setOutOrderNo(model.getOutOrderNo());
        recharge.setRemark(model.getRemark());
        int count = rechargeMapper.updateByPrimaryKeySelective(recharge);
        if (count == 1) {
            //根据审核状态更改账户，增加资金记录
            if (model.getStatus() == Recharge.STATUS.T3.code) {
                Account account = accountMapper.selectByUID(recharge.getUserId());
                //资金记录
                AccountLog accountLog = AccountLog.buildLog(recharge.getUserId(), recharge.getActualArrival(), AccountLog.TYPE.T1, account, "充值审核通过，操作金额：" + model.getActualArrival());
                accountLogMapper.insert(accountLog);
                //审核通过,增加可用,增加总额
                accountMapper.updateAccount(recharge.getActualArrival(), recharge.getActualArrival(), BigDecimal.ZERO, recharge.getUserId());
                // 发放积分
                pointRuleService.sendPoint(recharge.getUserId(), PointNid.T3);
                pointRuleService.sendPoint(recharge.getUserId(), PointNid.T4);
            }
        }
    }

    @Override
    public Map<String, BigDecimal> findFundMoney(Integer userId) {
        Map<String, BigDecimal> map = new HashMap<>();
        //获取充值总额
        BigDecimal rechargeMoney = rechargeMapper.findRechargeAllMoney(userId);
        map.put("rechargeMoney", rechargeMoney);
        //获取提现总金额
        BigDecimal cashMoney = cashMapper.findCashAllMoney(userId);
        map.put("cashMoney", cashMoney);
        return map;
    }

//    @Override
//    public MmmRecharge doRecharge(User user, BigDecimal amount) {
//        if (lockService.lock(LockId.RECHARGE + user.getId())) {
//            throw new BussinessException("您提交的充值请求正在处理，请勿重复提交");
//        }
//        try {
//            // 充值参数校验
//            if (amount == null || amount.compareTo(BigDecimal.ZERO) != 1) {
//                throw new BussinessException("充值金额有误");
//            }
//            amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
//            // 最低充值金额
//            BigDecimal min = redisService.get(ConfigNID.RECHARGE_MIN, BigDecimal.class);
//            if (min != null && min.compareTo(amount) == 1) {
//                throw new BussinessException("充值金额不能小于" + min + "元");
//            }
//            // 最高充值金额
//            BigDecimal max = redisService.get(ConfigNID.RECHARGE_MAX, BigDecimal.class);
//            if (max != null && max.compareTo(amount) == -1) {
//                throw new BussinessException("充值金额不能大于" + max + "元");
//            }
//
//            // 记录充值订单
//            String orderNo = OrderNoUtils.getSerialNumber();
//            Recharge model = new Recharge();
//            model.setUserId(user.getId());
//            model.setOrderNo(orderNo);
//            model.setAmount(amount);
//            model.setType(Recharge.TYPE.ONLINE.code);
//            model.setStatus(Recharge.STATUS.T1.code);
//            rechargeMapper.insert(model);
//
////            MmmRecharge mmm = MmmHelper.mmmRecharge(orderNo, user.getMmmId(), amount, "");
////            return mmm;
//            return null;
//        } finally {
//            // 释放锁
//            lockService.unlock(LockId.RECHARGE + user.getId());
//
//        }
//    }

    @Override
    public List<Recharge> selectExpired(Date expiredTime) {
        return rechargeMapper.selectExpired(expiredTime);
    }

    @Override
    public void doAlipayRecharge(User user, BigDecimal amount) {
        if (StringUtils.isBlank(user.getRealName())) {
            throw new BussinessException("请先实名");
        }
        if (StringUtils.isBlank(user.getAlipayAccount())) {
            throw new BussinessException("请先绑定支付宝账号");
        }
        if (BigDecimalUtils.isLessThan(amount, BigDecimal.ZERO)) {
            throw new BussinessException("充值金额有误");
        }
        amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
        // 最低充值金额
        BigDecimal min = redisService.get(ConfigNID.RECHARGE_MIN, BigDecimal.class);
        if (min != null && min.compareTo(amount) == 1) {
            throw new BussinessException("充值金额不能小于" + min + "元");
        }
        // 最高充值金额
        BigDecimal max = redisService.get(ConfigNID.RECHARGE_MAX, BigDecimal.class);
        if (max != null && max.compareTo(amount) == -1) {
            throw new BussinessException("充值金额不能大于" + max + "元");
        }
        // 记录充值订单
        String orderNo = OrderNoUtils.getSerialNumber();
        Recharge model = new Recharge();
        model.setUserId(user.getId());
        model.setOrderNo(orderNo);
        model.setAmount(amount);
        model.setType(Recharge.TYPE.T2.code);
        model.setStatus(Recharge.STATUS.T2.code);
        rechargeMapper.insert(model);
    }

    @Override
    public void handRecharge(Recharge recharge) {
        List<Recharge> recharge1 = rechargeMapper.select(new Recharge(r -> {
            r.setOutOrderNo(recharge.getOutOrderNo());
        }));
        if (null != recharge1 && recharge1.size() > 0) {
            throw new BussinessException("订单号已存在，请重新填写！");
        }
        String orderNo = OrderNoUtils.getSerialNumber();
        recharge.setOrderNo(orderNo);
        recharge.setActualArrival(recharge.getAmount());
        recharge.setFee(BigDecimal.ZERO);
        recharge.setFeePlat(BigDecimal.ZERO);
        recharge.setStatus(Recharge.STATUS.T3.code);
        recharge.setDelFlag(Recharge.DELFLAG.NORMAL.code);
        recharge.setCreateTime(new Date());
        rechargeMapper.insert(recharge);
        UserFreeze uFreezes = userFreezeMapper.selectOne(new UserFreeze(uf -> {
            uf.setUserId(recharge.getUserId());
            uf.setDelFlag(UserFreeze.DELFLAG.NORMAL.code);
        }));
        if (uFreezes.getFreezeRecharge().intValue() == UserFreeze.STATUS.T2.code) {
            throw new BussinessException("用户充值已冻结，请解冻！");
        }
        Account account = accountMapper.selectByUID(recharge.getUserId());
        //资金记录
        AccountLog accountLog = AccountLog.buildLog(recharge.getUserId(), recharge.getAmount(), AccountLog.TYPE.T12, account, "手动入金：" + recharge.getAmount() + "元");
        accountLogMapper.insert(accountLog);
        //增加资金
        accountMapper.updateAccount(recharge.getAmount(), recharge.getAmount(), BigDecimal.ZERO, recharge.getUserId());
        // 发放积分
        pointRuleService.sendPoint(recharge.getUserId(), PointNid.T3);
        pointRuleService.sendPoint(recharge.getUserId(), PointNid.T4);
    }

    @Override
    public BigDecimal selectSumAmountByType(int in, Integer agentId, String startTime, String endTime, Integer... types) {
        Map<String, Object> params = new HashMap<>();
        String inStr;
        if (in == 1) {
            inStr = " in ";
        } else {
            inStr = " not in ";
        }
        String typeStr = "";
        for (Integer type : types) {
            typeStr += type + ",";
        }
        typeStr = typeStr.substring(0, typeStr.length() - 1);
        String timeSql = "";
        if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
            timeSql = " AND t.create_time <= '" + endTime + "' AND t.create_time >= '" + startTime + "' ";
        }
        String agentSql = "";
        if (StringUtils.isNotBlank(agentId)) {
            agentSql = " AND user.agent_id = " + agentId;
        }
        String whereSql = " AND  t.type " + inStr + "(" + typeStr + ") AND t.`status` = " + Recharge.STATUS.T3.code + " AND t.del_flag = 1" + timeSql + agentSql;
        params.put("whereSql", whereSql);
        return rechargeMapper.selectSumAmountByType(params);
    }

    @Override
    public boolean createOrder(User user, String amount, String orderId) {
        //基本参数校验
        if (null == user || StringUtils.isBlank(amount) || StringUtils.isBlank(orderId)) {
            throw new BussinessException("充值参数缺失");
        }
        Recharge recharge = new Recharge();
        recharge.setType(Recharge.TYPE.T1.code);
        recharge.setOrderNo(orderId);
        recharge.setAmount(new BigDecimal(amount));
        recharge.setFee(BigDecimal.ZERO);
        recharge.setFeePlat(BigDecimal.ZERO);
        recharge.setStatus(Recharge.STATUS.T1.code);
        recharge.setDelFlag(Recharge.DELFLAG.NORMAL.code);
        recharge.setCreateTime(new Date());
        recharge.setUserId(user.getId());
        return rechargeMapper.insert(recharge) > 0;
    }

    @Override
    public void handleRechargeByUmpay(String tradeNo, String orderId, String amount, String tradeState, String errorCode, String paySeq,
                                      String usrPayAgreementId, String gateId, String lastFourCardId) {
        //主要业务参数判断
        if (StringUtils.isBlank(amount) || StringUtils.isBlank(orderId)) {
            log.error("处理订单参数缺失,终止处理...");
            return;
        }
        //通过订单号 用户id查询充值订单
        Recharge recharge = this.findByUserIdAndOrderNo(orderId);
        if (Objects.equals(ResultCode.TradeStateEnum.TRADE_SUCCESS.getCode(), tradeState)) {
            //判断订单状态和订单金额
            if (null != recharge && recharge.getStatus() == Recharge.STATUS.T1.code) {
                //转换后的订单金额
                BigDecimal transferAmount = BigDecimalUtils.mul(recharge.getAmount(), 100d);
                if (transferAmount.doubleValue() == new BigDecimal(amount).doubleValue()) {
                    // 处理用户资金和记录资金日志
                    Account account = accountMapper.selectByUID(recharge.getUserId());

                    //资金记录
                    accountLogMapper.insert(new AccountLog(accountLog -> {
                        accountLog.setCreateTime(new Date());
                        accountLog.setDelFlag(AccountLog.DELFLAG.NORMAL.code);
                        accountLog.setDirection(AccountLog.DIRECTION.RECEIVE.code);
                        accountLog.setAmount(recharge.getAmount());
                        accountLog.setUserId(recharge.getUserId());
                        accountLog.setTotal(account.getTotal());
                        accountLog.setAvailable(account.getAvailable());
                        accountLog.setFreeze(account.getFreeze());
                        accountLog.setType(AccountLog.TYPE.T1.code);
                        accountLog.setRemark("快捷支付入金：" + recharge.getAmount() + "元");
                    }));
                    //更新用户资金账户
                    accountMapper.updateAccount(recharge.getAmount(), recharge.getAmount(), BigDecimal.ZERO, recharge.getUserId());

                    //处理充值订单
                    recharge.setActualArrival(recharge.getAmount());
                    recharge.setUpdateTime(new Date());
                    recharge.setOutOrderNo(tradeNo);
                    recharge.setOutStatus(tradeState);
                    recharge.setRemark("支付成功,支付协议号:[" + usrPayAgreementId + "]");
                    recharge.setBankNo(lastFourCardId);
                    recharge.setBankName(gateId);
                    recharge.setOutMsg("支付成功,银行流水号:[" + paySeq + "]");
                    recharge.setStatus(Recharge.STATUS.T3.code);
                    rechargeMapper.updateByPrimaryKeySelective(recharge);

                    // 发放积分
                    pointRuleService.sendPoint(recharge.getUserId(), PointNid.T3);
                    pointRuleService.sendPoint(recharge.getUserId(), PointNid.T4);
                } else {
                    log.error("订单支付金额与回调金额不一致");
                }
            } else {
                log.error("订单不存在或已处理");
            }
        } else {
            //处理充值订单
            recharge.setActualArrival(BigDecimal.ZERO);
            recharge.setUpdateTime(new Date());
            recharge.setOutOrderNo(tradeNo);
            recharge.setOutStatus(tradeState);
            recharge.setRemark("支付失败 第三方直白代码:" + errorCode);
            recharge.setBankNo(lastFourCardId);
            recharge.setBankName(gateId);
            recharge.setOutMsg(ResultCode.ErrorCodeEnum.msgOf(errorCode));
            recharge.setStatus(Recharge.STATUS.T4.code);
            rechargeMapper.updateByPrimaryKeySelective(recharge);
        }
    }

    @Override
    public void handleRechargeByLianLian(PayDataBean payDataBean) {
        try {
            // 主要业务参数判断
            if (StringUtils.isBlank(payDataBean.getMoney_order()) || StringUtils.isBlank(payDataBean.getOid_paybill())) {
                log.error("处理订单参数缺失,终止处理...");
                throw new BussinessException("处理订单参数缺失,终止处理...");
            }
            // 通过订单号 用户id查询充值订单
            Recharge recharge = this.findByUserIdAndOrderNo(payDataBean.getNo_order());
            if (recharge == null) throw new BussinessException("充值订单不存在。");
            if (recharge.getStatus().intValue() == Recharge.STATUS.T3.code)
                throw new BussinessException("充值订单已处理，订单ID：" + recharge.getId());

            if (Objects.equals(PayResultEnum.SUCCESS.getCode(), payDataBean.getResult_pay())) {
                //判断订单状态和订单金额
                if (recharge.getStatus() != Recharge.STATUS.T3.code) {
                    // 实际到账金额
                    BigDecimal amount = new BigDecimal(payDataBean.getMoney_order());

                    // 处理用户资金和记录资金日志
                    Account a = accountMapper.selectByUID(recharge.getUserId());
                    if (a == null) throw new BussinessException("查询用户资金账户失败");
                    AccountLog log = AccountLog.buildLog(a.getUserId(), amount, AccountLog.TYPE.T1, a, "快捷支付入金：" + amount + "元");
                    if (accountLogMapper.insert(log) != 1) throw new BussinessException("充值保存资金记录失败");
                    if (accountMapper.updateAccount(amount, amount, BigDecimal.ZERO, recharge.getUserId()) != 1)
                        throw new BussinessException("充值更新用户账户信息失败");

                    //处理充值订单
                    recharge.setActualArrival(amount);
                    recharge.setUpdateTime(new Date());
                    recharge.setRemark("连连支付充值成功");
                    recharge.setStatus(Recharge.STATUS.T3.code);
                    recharge.setOutOrderNo(payDataBean.getOid_paybill());
                    recharge.setOutStatus(payDataBean.getResult_pay());
                    recharge.setOutMsg(JSON.toJSONString(payDataBean));
                    rechargeMapper.updateByPrimaryKeySelective(new Recharge(t -> {
                        t.setId(recharge.getId());
                        t.setActualArrival(amount);
                        t.setUpdateTime(new Date());
                        t.setRemark("连连支付充值成功");
                        t.setStatus(Recharge.STATUS.T3.code);
                        t.setOutOrderNo(payDataBean.getOid_paybill());
                        t.setOutStatus(payDataBean.getResult_pay());
                        t.setOutMsg(JSON.toJSONString(payDataBean));
                    }));

                    // 发放积分
                    pointRuleService.sendPoint(recharge.getUserId(), PointNid.T3);
                    pointRuleService.sendPoint(recharge.getUserId(), PointNid.T4);

                    // 缓存回调结果
                    redisService.put(CacheID.PAY_RESULT + payDataBean.getInfo_order(), PayResult.success("恭喜您，充值成功", ""), 30 * 60);
                } else {
                    log.error("充值订单已处理，订单ID：" + recharge.getId());
                }
            } else {
                //处理充值订单
                rechargeMapper.updateByPrimaryKeySelective(new Recharge(t -> {
                    t.setId(recharge.getId());
                    t.setActualArrival(BigDecimal.ZERO);
                    t.setUpdateTime(new Date());
                    t.setRemark("连连支付充值失败");
                    t.setStatus(Recharge.STATUS.T4.code);
                    t.setOutStatus(payDataBean.getResult_pay());
                    t.setOutMsg(JSON.toJSONString(payDataBean));
                }));
                recharge.setActualArrival(BigDecimal.ZERO);
                recharge.setUpdateTime(new Date());
                recharge.setOutStatus(payDataBean.getResult_pay());
                recharge.setRemark("连连支付充值失败");
                recharge.setStatus(Recharge.STATUS.T4.code);
                recharge.setOutMsg(JSON.toJSONString(payDataBean));
                rechargeMapper.updateByPrimaryKeySelective(recharge);

                redisService.put(CacheID.PAY_RESULT + payDataBean.getInfo_order(), PayResult.failed("抱歉，充值失败", ""), 30 * 60);
            }
        } catch (BussinessException e) {
            e.printStackTrace();
            redisService.put(CacheID.PAY_RESULT + payDataBean.getInfo_order(), PayResult.failed(e.getMessage(), ""), 30 * 60);
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            redisService.put(CacheID.PAY_RESULT + payDataBean.getInfo_order(), PayResult.failed("系统繁忙，请到账户中心核对", ""), 30 * 60);
            throw e;
        }
    }

    @Override
    public Recharge findByUserIdAndOrderNo(String orderId) {
        if (StringUtils.isBlank(orderId)) {
            throw new BussinessException("查询订单参数缺失");
        }
        return rechargeMapper.findByUserIdAndOrderNo(orderId);
    }

    @Override
    public String doRechargeByEtone(String amount, Integer userId, String baseUrl) throws Exception {
        User user = userMapper.selectByPrimaryKey(userId);
        if (StringUtils.isBlank(user.getRealName())) {
            throw new BussinessException("请先通过实名认证");
        }
        //校验用户充值是否冻结
        UserFreeze userFreeze = userFreezeMapper.selectOne(new UserFreeze(f -> {
            f.setDelFlag(UserFreeze.DELFLAG.NORMAL.code);
            f.setUserId(user.getId());
        }));
        if (null != userFreeze && UserFreeze.STATUS.T1.code != userFreeze.getFreezeRecharge()) {
            throw new BussinessException("您的账户充值功能已被冻结，请联系客服处理");
        }
        if (StringUtils.isBlank(amount) || Constants.CONS_ZERO.equals(amount)) {
            throw new BussinessException("充值金额不正确");
        }
        if (!ValidateUtils.isMoney(amount)) {
            throw new BussinessException("充值金额不正确");
        }
        // 保存充值订单
        Recharge recharge = new Recharge(t -> {
            t.setUserId(userId);
            t.setType(Recharge.TYPE.T1.code);
            t.setOrderNo(OrderNoUtils.getETRechargeOrderNo());
            t.setAmount(new BigDecimal(amount));
            t.setFee(BigDecimal.ZERO);
            t.setFeePlat(BigDecimal.ZERO);
            t.setStatus(Recharge.STATUS.T1.code);
            t.setDelFlag(Recharge.DELFLAG.NORMAL.code);
            t.setCreateTime(new Date());
        });
        if (rechargeMapper.insert(recharge) != 1) throw new BussinessException("新增充值记录失败");
        // 支付单标识
        String hmTk = UUID.randomUUID().toString();
        // 商户返回地址
        String merURL = baseUrl + "result?hm_tk=" + hmTk;
        // 异步回调地址
        String backURL = baseUrl + "api/notify/etone/payNotify";
        // 处理充值金额  单位为分
        String tranAmt = String.valueOf(new BigDecimal(amount).multiply(new BigDecimal(100)).intValue());
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        // 准备支付参数
        PayForm payForm = EtonePayUtil.buildForm(recharge.getOrderNo(), tranAmt, recharge.getOrderNo(), "", "", "", "", "", hmTk, "", "", "", format.format(new Date()), merURL, backURL);
        // 返回支付链接
        return EtonePayUtil.getPayUrl(payForm);
    }

    @Override
    public void doRechargeBackEtone(BackForm backForm, String hmTk) {
        try {
            String orderNo = backForm.getMerOrderNum();
            Recharge recharge = rechargeMapper.selectOne(new Recharge(t -> {
                t.setOrderNo(orderNo);
            }));
            if (recharge == null) throw new BussinessException("查询充值订单失败");

            if (recharge.getStatus().intValue() != Recharge.STATUS.T1.code) throw new BussinessException("订单状态错误");
            if ("0000".equals(backForm.getRespCode())) {
                // 实际入账金额
                BigDecimal actualArrival = new BigDecimal(backForm.getTranAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                // 手续费
                BigDecimal fee = new BigDecimal(backForm.getBankFeeAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                // 支付成功，更新订单信息
                if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                    t.setId(recharge.getId());
                    t.setVersion(recharge.getVersion());
                    t.setOutOrderNo(backForm.getOrderId());
                    t.setStatus(Recharge.STATUS.T3.code);
                    t.setActualArrival(actualArrival);
                    t.setFeePlat(fee);
                    t.setOutStatus(backForm.getRespCode());
                    t.setOutMsg(JSON.toJSONString(backForm));
                })) != 1) throw new BussinessException("更新充值记录失败");
                // 更新用户资金
                Account a = accountMapper.selectByUID(recharge.getUserId());
                if (a == null) throw new BussinessException("查询用户资金账户失败");
                AccountLog log = AccountLog.buildLog(a.getUserId(), actualArrival, AccountLog.TYPE.T1, a, "充值成功");
                if (accountLogMapper.insert(log) != 1) throw new BussinessException("充值保存资金记录失败");
                if (accountMapper.updateAccount(actualArrival, actualArrival, BigDecimal.ZERO, a.getUserId()) != 1)
                    throw new BussinessException("充值更新用户账户信息失败");

                // 发放积分
                pointRuleService.sendPoint(a.getUserId(), PointNid.T3);
                pointRuleService.sendPoint(a.getUserId(), PointNid.T4);

                // 缓存回调结果
                redisService.put(CacheID.PAY_RESULT + hmTk, PayResult.success("恭喜您，充值成功", ""), 30 * 60);
            } else if ("9999".equals(backForm.getRespCode())) {
                // 支付失败，更新订单信息
                if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                    t.setId(recharge.getId());
                    t.setVersion(recharge.getVersion());
                    t.setOutOrderNo(backForm.getOrderId());
                    t.setStatus(Recharge.STATUS.T4.code);
                    t.setOutStatus(backForm.getRespCode());
                    t.setOutMsg(JSON.toJSONString(backForm));
                })) != 1) throw new BussinessException("更新充值记录失败");

                // 缓存回调结果
                redisService.put(CacheID.PAY_RESULT + hmTk, PayResult.failed("抱歉，充值失败", ""), 30 * 60);
            } else if ("8888".equals(backForm.getRespCode())) {
                // 未支付，更新订单信息
                if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                    t.setId(recharge.getId());
                    t.setVersion(recharge.getVersion());
                    t.setOutOrderNo(backForm.getOrderId());
                    t.setStatus(Recharge.STATUS.T4.code);
                    t.setOutStatus(backForm.getRespCode());
                    t.setOutMsg(JSON.toJSONString(backForm));
                })) != 1) throw new BussinessException("更新充值记录失败");

                // 缓存回调结果
                redisService.put(CacheID.PAY_RESULT + hmTk, PayResult.failed("抱歉，充值失败", ""), 30 * 60);
            }
        } catch (BussinessException e) {
            // 缓存回调结果
            redisService.put(CacheID.PAY_RESULT + hmTk, PayResult.failed(e.getMessage(), ""), 30 * 60);
        } catch (Exception e) {
            // 缓存回调结果
            redisService.put(CacheID.PAY_RESULT + hmTk, PayResult.failed("系统繁忙，请到账户中心核对", ""), 30 * 60);
        }


    }

    @Override
    public BigDecimal findRechargeAllMoney(Integer userId) {
        return rechargeMapper.findRechargeAllMoney(userId);
    }

    @Override
    public PaymentInfo doRechargeByLianLian(Integer userId, Integer bankId, String hmTk, String amount) {
        User user = userMapper.selectByPrimaryKey(userId);
        if (null == user) {
            throw new BussinessException("登录失效，请重新登录");
        }
        if (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard())) {
            throw new BussinessException("请先进行实名认证");
        }
        UserBank bank = userBankMapper.selectByPrimaryKey(bankId);
        if (bank == null) {
            throw new BussinessException("充值银行卡未绑定");
        }

        // 新增充值记录
        Recharge recharge = new Recharge();
        recharge.setBankName(bank.getBankName());
        recharge.setBankNo(bank.getBankNo());
        recharge.setBranch(bank.getBranch());
        recharge.setUserId(user.getId());
        recharge.setOrderNo(OrderNoUtils.getLLRechargeOrderNo());
        recharge.setAmount(new BigDecimal(amount));
        recharge.setType(Recharge.TYPE.T1.code);
        recharge.setRemark(hmTk);
        recharge.setStatus(Recharge.STATUS.T1.code);
        recharge.setDelFlag(Recharge.DELFLAG.NORMAL.code);
        if (rechargeMapper.insert(recharge) != 1) throw new BussinessException("保存充值记录失败");

        // 构造支付请求对象
        PaymentInfo paymentInfo = new PaymentInfo();
        paymentInfo.setVersion(PartnerConfig.VERSION);
        paymentInfo.setOid_partner(PartnerConfig.OID_PARTNER);
        paymentInfo.setUser_id(user.getId().toString());
        paymentInfo.setApp_request(PartnerConfig.WAP);
        paymentInfo.setSign_type(PartnerConfig.SIGN_TYPE);
        paymentInfo.setBusi_partner(PartnerConfig.BUSI_PARTNER);
        paymentInfo.setNo_order(recharge.getOrderNo());
        paymentInfo.setDt_order(DateUtils.dateStr(new Date(), "yyyyMMddHHmmss"));
        paymentInfo.setName_goods("用户充值");
        paymentInfo.setInfo_order(hmTk);
        paymentInfo.setMoney_order(amount);
        String webUrl = redisService.get(ConfigNID.WEB_SERVER_URL);
        paymentInfo.setNotify_url(webUrl + PartnerConfig.NOTIFY_URL);
        paymentInfo.setUrl_return(webUrl + "result?hm_tk=" + hmTk);
        paymentInfo.setValid_order("10080");// 单位分钟，可以为空，默认7天
        paymentInfo.setRisk_item(createRiskItem(user));
        // 商戶从自己系统中获取用户身份信息(认证支付必须将用户身份信息传输给连连，且修改标记flag_modify设置成1：不可修改)
        paymentInfo.setId_type("0");
        paymentInfo.setId_no(user.getIdCard());
        paymentInfo.setAcct_name(user.getRealName());
        paymentInfo.setFlag_modify("1");
//        if (StringUtils.isNotBlank(noAgree)) { // 协议号和卡号同时存在时，优先将协议号送给连连，不要将协议号和卡号都送给连连
//           paymentInfo.setNo_agree(noAgree);
//        }
        paymentInfo.setCard_no(bank.getBankNo());
        // 加签名
        String sign = YinTongUtil.addSign(JSON.parseObject(JSON.toJSONString(paymentInfo)), PartnerConfig.TRADER_PRI_KEY, PartnerConfig.MD5_KEY);
        paymentInfo.setSign(sign);

        return paymentInfo;
    }


    @Override
    public void doRechargeByNinePai(Integer userId, String checkCode) {
        // 获取快捷支付参数
        Map<String, String> paramsMap = redisService.get(CacheID.NINE_PAI_RECHARGE + userId, Map.class);
        if (null == paramsMap || paramsMap.size() <= 0) throw new BussinessException("充值标识错误，或充值信息不存在");
        // 清除重新参数缓存
        redisService.del(CacheID.NINE_PAI_RECHARGE + userId);
        // 充值银行卡信息
        String contractId = paramsMap.get("contractId");
        UserBank bank = userBankMapper.selectOne(new UserBank(t -> t.setContractId(contractId)));
        if (bank == null) throw new BussinessException("绑卡协议号错误");

        // 保存充值信息
        Recharge recharge = new Recharge();
        recharge.setType(Recharge.TYPE.T1.code);
        recharge.setUserId(Integer.parseInt(paramsMap.get("memberId")));
        recharge.setAmount(new BigDecimal(paramsMap.get("amount")).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
        recharge.setStatus(Recharge.STATUS.T1.code);
        recharge.setOrderNo(paramsMap.get("orderId"));
        recharge.setBankName(bank.getBankName());
        recharge.setBankNo(bank.getBankNo());
        recharge.setBranch(bank.getBranch());
        if (rechargeMapper.insert(recharge) != 1) throw new BussinessException("保存充值信息失败");

        // 提交充值信息
        RpmUtils.doQuickPayCommit(paramsMap, checkCode);
    }

    @Override
    public void doRechargeBackNinePai(Map<String, String> dataMap) {
//        try {
        String orderNo = dataMap.get("orderId");
        Recharge recharge = rechargeMapper.selectOne(new Recharge(t -> {
            t.setOrderNo(orderNo);
        }));
        if (recharge == null) throw new BussinessException("查询充值订单失败");

        if (recharge.getStatus().intValue() == Recharge.STATUS.T3.code) throw new BussinessException("订单已处理");
        if ("PD".equals(dataMap.get("orderSts"))) { // 支付成功
            // 实际入账金额
            BigDecimal actualArrival = new BigDecimal(dataMap.get("amount")).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            // 手续费
            BigDecimal fee = new BigDecimal(dataMap.get("fee")).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            // 支付成功，更新订单信息
            if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                t.setId(recharge.getId());
                t.setVersion(recharge.getVersion());
                t.setStatus(Recharge.STATUS.T3.code);
                t.setActualArrival(actualArrival);
                t.setFeePlat(fee);
                t.setOutStatus(dataMap.get("orderSts"));
                t.setOutMsg(JSON.toJSONString(dataMap));
            })) != 1) throw new BussinessException("更新充值记录失败");
            // 更新用户资金
            Account a = accountMapper.selectByUID(recharge.getUserId());
            if (a == null) throw new BussinessException("查询用户资金账户失败");
            AccountLog log = AccountLog.buildLog(a.getUserId(), actualArrival, AccountLog.TYPE.T1, a, "充值成功");
            if (accountLogMapper.insert(log) != 1) throw new BussinessException("充值保存资金记录失败");
            if (accountMapper.updateAccount(actualArrival, actualArrival, BigDecimal.ZERO, a.getUserId()) != 1)
                throw new BussinessException("充值更新用户账户信息失败");

            // 发放积分
            pointRuleService.sendPoint(a.getUserId(), PointNid.T3);
            pointRuleService.sendPoint(a.getUserId(), PointNid.T4);

//                // 缓存回调结果
//                redisService.put(CacheID.PAY_RESULT + recharge.getOutOrderNo(), PayResult.success("恭喜您，充值成功", ""), 30 * 60);
        } else {
            // 支付失败，更新订单信息
            if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                t.setId(recharge.getId());
                t.setVersion(recharge.getVersion());
                t.setStatus(Recharge.STATUS.T4.code);
                t.setOutStatus(dataMap.get("orderSts"));
                t.setOutMsg(JSON.toJSONString(dataMap));
            })) != 1) throw new BussinessException("更新充值记录失败");

//                // 缓存回调结果
//                redisService.put(CacheID.PAY_RESULT + hmTk, PayResult.failed("抱歉，充值失败", ""), 30 * 60);
        }
//        } catch (BussinessException e) {
//            // 缓存回调结果h
//            redisService.put(CacheID.PAY_RESULT + mTk, PayResult.failed(e.getMessage(), ""), 30 * 60);
//        } catch (Exception e) {
//            // 缓存回调结果
//            redisService.put(CacheID.PAY_RESULT + recharge.getOutOrderNo(), PayResult.failed("系统繁忙，请到账户中心核对", ""), 30 * 60);
//        }
    }

    @Override
    public void doRechargeByHR(Integer userId, String checkCode) throws Exception {
        // 获取快捷支付参数
        Map<String, String> resDataMap = redisService.get(CacheID.HR_PAY_RECHARGE + userId, Map.class);
        if (null == resDataMap || resDataMap.size() <= 0) throw new BussinessException("充值订单已过期，请重新发送短信验证码");
        // 清除重新参数缓存
        redisService.del(CacheID.HR_PAY_RECHARGE + userId);

        // 充值订单号
        String orderNo = resDataMap.get("orderNo");
        UserBank bank = userBankMapper.selectOne(new UserBank(t -> {
            t.setBankNo(resDataMap.get("cardNo"));
            t.setDelFlag(GenericPo.DELFLAG.NORMAL.code);
            t.setUserId(userId);
        }));
        if (bank == null) throw new BussinessException("查询支付银行卡失败");

        // 保存充值信息
        Recharge recharge = new Recharge();
        recharge.setOrderNo(orderNo);
        recharge.setType(Recharge.TYPE.T1.code);
        recharge.setUserId(userId);
        recharge.setAmount(new BigDecimal(resDataMap.get("transAmt")).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
        recharge.setStatus(Recharge.STATUS.T1.code);
        recharge.setBankName(bank.getBankName());
        recharge.setBankNo(bank.getBankNo());
        recharge.setBranch(bank.getBranch());
        if (rechargeMapper.insert(recharge) != 1) throw new BussinessException("保存充值信息失败");

        // 提交充值信息
        Map<String, String> payDataMap = HRPayUtils.quickPay(checkCode, orderNo);

        if (!("0000".equals(payDataMap.get("respCode")) || "P000".equals(payDataMap.get("respCode"))))
            throw new BussinessException(payDataMap.get("respDesc"));
    }

    @Override
    public void doRechargeBackHR(Map<String, String> dataMap) {
        String orderNo = dataMap.get("orderNo");
        Recharge recharge = rechargeMapper.selectOne(new Recharge(t -> {
            t.setOrderNo(orderNo);
        }));
        if (recharge == null) throw new BussinessException("查询充值订单失败");

        if (recharge.getStatus().intValue() == Recharge.STATUS.T3.code) throw new BussinessException("订单已处理");
        if ("0000".equals(dataMap.get("respCode"))) { // 支付成功
            // 实际入账金额
            BigDecimal actualArrival = new BigDecimal(dataMap.get("transAmt")).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            // 支付成功，更新订单信息
            if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                t.setId(recharge.getId());
                t.setVersion(recharge.getVersion());
                t.setStatus(Recharge.STATUS.T3.code);
                t.setActualArrival(actualArrival);
                t.setOutStatus(dataMap.get("respCode"));
                t.setOutMsg(JSON.toJSONString(dataMap));
            })) != 1) throw new BussinessException("更新充值记录失败");
            // 更新用户资金
            Account a = accountMapper.selectByUID(recharge.getUserId());
            if (a == null) throw new BussinessException("查询用户资金账户失败");
            AccountLog log = AccountLog.buildLog(a.getUserId(), actualArrival, AccountLog.TYPE.T1, a, "充值成功");
            if (accountLogMapper.insert(log) != 1) throw new BussinessException("充值保存资金记录失败");
            if (accountMapper.updateAccount(actualArrival, actualArrival, BigDecimal.ZERO, a.getUserId()) != 1)
                throw new BussinessException("充值更新用户账户信息失败");

            // 发放积分
            pointRuleService.sendPoint(a.getUserId(), PointNid.T3);
            pointRuleService.sendPoint(a.getUserId(), PointNid.T4);

        } else if ("P000".equals(dataMap.get("respCode"))) {
            // 三方支付处理中，本地不处理
        } else {
            // 支付失败，更新订单信息
            if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                t.setId(recharge.getId());
                t.setVersion(recharge.getVersion());
                t.setStatus(Recharge.STATUS.T4.code);
                t.setOutStatus(dataMap.get("respCode"));
                t.setOutMsg(JSON.toJSONString(dataMap));
            })) != 1) throw new BussinessException("更新充值记录失败");
        }
    }

    @Override
    public void doRechargeByHRB2C(Integer userId,Integer bankId,Map<String,String> map) throws Exception {
        User user = userMapper.selectByPrimaryKey(userId);
        // 充值订单号
        String orderNo = map.get("orderNo");
        Bank bank = bankMapper.selectByPrimaryKey(bankId);
        // 保存充值信息
        Recharge recharge = new Recharge();
        recharge.setOrderNo(orderNo);
        recharge.setType(Recharge.TYPE.T1.code);
        recharge.setUserId(userId);
        recharge.setAmount(new BigDecimal(map.get("transAmt")).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
        recharge.setStatus(Recharge.STATUS.T1.code);
        recharge.setBankName(bank.getName());
        if (rechargeMapper.insert(recharge) != 1) throw new BussinessException("保存充值信息失败");
    }

    @Override
    public void doRechargeBackHRB2C(Map<String, String> dataMap) {
        String orderNo = dataMap.get("orderNo");
        Recharge recharge = rechargeMapper.selectOne(new Recharge(t -> {
            t.setOrderNo(orderNo);
        }));
        if (recharge == null) throw new BussinessException("查询充值订单失败");
        if (recharge.getStatus().intValue() != Recharge.STATUS.T1.code) throw new BussinessException("订单已处理");
        if ("0000".equals(dataMap.get("respCode"))) { // 支付成功
            // 实际入账金额
            BigDecimal actualArrival = new BigDecimal(dataMap.get("transAmt")).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
            // 支付成功，更新订单信息
            if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                t.setId(recharge.getId());
                t.setVersion(recharge.getVersion());
                t.setStatus(Recharge.STATUS.T3.code);
                t.setActualArrival(actualArrival);
                t.setOutStatus(dataMap.get("respCode"));
                t.setOutMsg(JSON.toJSONString(dataMap));
            })) != 1) throw new BussinessException("更新充值记录失败");
            // 更新用户资金
            Account a = accountMapper.selectByUID(recharge.getUserId());
            if (a == null) throw new BussinessException("查询用户资金账户失败");
            AccountLog log = AccountLog.buildLog(a.getUserId(), actualArrival, AccountLog.TYPE.T1, a, "充值成功");
            if (accountLogMapper.insert(log) != 1) throw new BussinessException("充值保存资金记录失败");
            if (accountMapper.updateAccount(actualArrival, actualArrival, BigDecimal.ZERO, a.getUserId()) != 1)
                throw new BussinessException("充值更新用户账户信息失败");

            // 发放积分
            pointRuleService.sendPoint(a.getUserId(), PointNid.T3);
            pointRuleService.sendPoint(a.getUserId(), PointNid.T4);

        } else if ("P000".equals(dataMap.get("respCode"))) {
            // 三方支付处理中，本地不处理
        } else {
            // 支付失败，更新订单信息
            if (rechargeMapper.updateByIdAndVersionSelective(new Recharge(t -> {
                t.setId(recharge.getId());
                t.setVersion(recharge.getVersion());
                t.setStatus(Recharge.STATUS.T4.code);
                t.setOutStatus(dataMap.get("respCode"));
                t.setOutMsg(JSON.toJSONString(dataMap));
            })) != 1) throw new BussinessException("更新充值记录失败");
        }
    }


    /**
     * 根据连连支付风控部门要求的参数进行构造风控参数
     *
     * @return
     */
    private String createRiskItem(User user) {
        JSONObject riskItemObj = new JSONObject();
        riskItemObj.put("frms_ware_category", "2026");//商品类目
        riskItemObj.put("user_info_mercht_userno", String.valueOf(user.getId()));//你们平台的用户id
        riskItemObj.put("user_info_dt_register", DateUtils.dateStr3(user.getCreateTime()));//注册时间
        riskItemObj.put("user_info_bind_phone", user.getMobile());//绑定手机号
        if (StringUtils.isBlank(user.getRealName())) {
            riskItemObj.put("user_info_identify_state", "1");//已经实名认证
        } else {
            riskItemObj.put("user_info_identify_state", "0");//没有实名认证
        }
        riskItemObj.put("user_info_identify_state", "1");//已经实名认证
        riskItemObj.put("user_info_identify_type", "1");//实名认证方式
        riskItemObj.put("user_info_full_name", user.getRealName());//用户姓名
        riskItemObj.put("user_info_id_no", user.getIdCard());//用户身份证号
        return riskItemObj.toString();
    }
}
